#include"protocolswitcher.h"

ProtocolSwitcher::ProtocolSwitcher(QWidget *parent)
    : QWidget(parent),
      udpSocket(nullptr),
      tcpSocket(nullptr)
{
    // UI Setup
    QVBoxLayout *layout = new QVBoxLayout(this);

    protocolComboBox = new QComboBox();
    protocolComboBox->addItem("UDP Unicast");
    protocolComboBox->addItem("UDP Multicast");
    protocolComboBox->addItem("UDP Broadcast");
    protocolComboBox->addItem("TCP");

    sendButton = new QPushButton("Send Message");

    checkbox = new QCheckBox("存盘");
    cycleCheckbox = new QCheckBox("循环");
    QHBoxLayout *Hlayout = new QHBoxLayout;
    Hlayout->addWidget(checkbox);
    Hlayout->addWidget(cycleCheckbox);

    sendTextEdit = new QTextEdit();
    sendSourTextEdit = new QTextEdit();
    outputTextEdit = new QTextEdit();

    outputTextEdit->setReadOnly(true);
    layout->addWidget(protocolComboBox);
    layout->addWidget(sendButton);
    layout->addLayout(Hlayout);
    layout->addWidget(sendTextEdit);
    layout->addWidget(sendSourTextEdit);
    layout->addWidget(outputTextEdit);

    // Connections
    connect(protocolComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(onProtocolChanged(int)));
    connect(sendButton, SIGNAL(clicked()), this, SLOT(onSendMessage()));
    connect(checkbox, &QCheckBox::toggled, this, &ProtocolSwitcher::onCheckBoxToggled);
    connect(cycleCheckbox, &QCheckBox::toggled, this, &ProtocolSwitcher::onCycleCheckboxToggled);


    TimerExample();
    // Default to UDP Unicast
    loadConfigFromXml("config.xml");
    onProtocolChanged(0);
    resize(500,600);


}

void ProtocolSwitcher::onProtocolChanged(int index)
{
    // Clean up old sockets
    if (udpSocket)
    {
        udpSocket->close();
        delete udpSocket;
        udpSocket = nullptr;
    }
    if (tcpSocket)
    {
        tcpSocket->disconnectFromHost();
        tcpSocket->close();
        delete tcpSocket;
        tcpSocket = nullptr;
    }

    // Set the selected protocol
    if (index == 0) // UDP Unicast
    {
        udpSocket = new QUdpSocket(this);
                   udpSocket->bind(QHostAddress::Any,udpA_softUnicastPort);
                   //qDebug()<<udpUnicastPort;
        connect(udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDataReceived()));
        outputTextEdit->append("Switched to UDP Unicast.");
    }
    else if (index == 1) // UDP Multicast
    {
        udpSocket = new QUdpSocket(this);
        // Bind to IPv4 address, and then join multicast group
        if (udpSocket->bind(QHostAddress::AnyIPv4, udpA_softMulticastPort, QUdpSocket::ShareAddress)) {
            udpSocket->joinMulticastGroup(QHostAddress(udpA_softMulticastHost)); // Example multicast address
            connect(udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDataReceived()));
            outputTextEdit->append("Switched to UDP Multicast.");
        } else {
            outputTextEdit->append("Failed to bind UDP socket for Multicast.");
        }
    }
    else if (index == 2) // UDP Broadcast
    {
        udpSocket = new QUdpSocket(this);
        if (udpSocket->bind(QHostAddress::AnyIPv4, udpA_softBroadcastPort, QUdpSocket::ShareAddress)) {
            connect(udpSocket, SIGNAL(readyRead()), this, SLOT(onUdpDataReceived()));
            outputTextEdit->append("Switched to UDP Broadcast.");
        } else {
            outputTextEdit->append("Failed to bind UDP socket for Broadcast.");
        }
    }
    else if (index == 3) // TCP
    {
        //            connect(tcpSocket, SIGNAL(error(QAbstractSocket::SocketError)),
        //                            this, SLOT(onTcpError(QAbstractSocket::SocketError)));  // 使用传统信号槽连接方式
        tcpSocket = new QTcpSocket(this);
        tcpServer = new QTcpServer(this);

        if (!tcpServer->listen(QHostAddress::Any, tcpPort)) {
            qDebug() << "Server could not start!";
            return;
        }

        connect(tcpServer, &QTcpServer::newConnection, this, &ProtocolSwitcher::onTcpConnected);
        //connect(tcpSocket, &QTcpSocket::connected, this, &ProtocolSwitcher::onTcpConnected);
    }
}

void ProtocolSwitcher::onSendMessage()
{//       // 初始化结构体并填充数据
    // 将结构体数据转为 QByteArray

    Data data;
    data.head = 0xEB90;
    data.tail = 0x0D0A;
    data.type = 0;  // 可以根据需要初始化其他成员
    data.dataType = 0;  // 根据需要初始化

    QString msg = sendTextEdit->toPlainText();
    data.info = msg;

    // 计算 data.message 的长度
    data.dataLong = data.info.length();

    //QByteArray message((const char*)&data, sizeof(data));
    // 将结构体的内容转换为 QByteArray 进行发送
//    QByteArray message;
////    QDataStream stream(&message, QIODevice::WriteOnly);
////    stream << data.head
////           << data.type
////           << data.dataType
////           << data.dataLong;
////           << data.info
////           << data.tail;
//    message.append(reinterpret_cast<const char*>(&data.head), sizeof(data.head));
//    message.append(reinterpret_cast<const char*>(&data.type), sizeof(data.type));
//    message.append(reinterpret_cast<const char*>(&data.dataType), sizeof(data.dataType));
//    message.append(reinterpret_cast<const char*>(&data.dataLong), sizeof(data.dataLong));
//    message.append(data.info.toUtf8());  // 确保按 UTF-8 编码加入字符串
//    message.append(reinterpret_cast<const char*>(&data.tail), sizeof(data.tail));
//    qDebug() << QString("0x%1").arg(data.head, 0, 16).toUpper();  // 方法 1


    QByteArray message;
    QDataStream stream(&message, QIODevice::WriteOnly);
    //stream.setByteOrder(QDataStream::BigEndian);  // 使用大端字节序

    // 注意顺序按结构体字段顺序写入
    stream << data.head;
    stream << data.type;
    stream << data.dataType;
    stream << data.dataLong;

    // 添加字符串到字节数组
    stream.writeRawData(data.info.toUtf8().data(), data.info.length());  // 写入字符串信息
    stream << data.tail;
    sendData(message);
}
void ProtocolSwitcher::sendData(QByteArray message)
{
    if (protocolComboBox->currentIndex() == 0) // UDP Unicast
    {
        // Send UDP Unicast message
        //QByteArray message = "Hello from UDP Unicast!";
        udpSocket->writeDatagram(message, QHostAddress(udpB_softUnicastHost), udpB_softUnicastPort);
        sendSourTextEdit->append("Sent UDP Unicast message: ");
    }
    else if (protocolComboBox->currentIndex() == 1) // UDP Multicast
    {
        // Send UDP Multicast message
        //QByteArray message = "Hello from UDP Multicast!";
        udpSocket->writeDatagram(message, QHostAddress(udpB_softMulticastHost), udpB_softMulticastPort); // Multicast address
        sendSourTextEdit->append("Sent UDP Multicast message: ");
    }
    else if (protocolComboBox->currentIndex() == 2) // UDP Broadcast
    {
        // Send UDP Broadcast message
        //QByteArray message = "Hello from UDP Broadcast!";
        udpSocket->writeDatagram(message, QHostAddress::Broadcast, udpB_softBroadcastPort);
        sendSourTextEdit->append("Sent UDP Broadcast message: ");
    }
    else if (protocolComboBox->currentIndex() == 3) // TCP
    {
        // Send TCP message (only after connected)
        if (tcpSocket->state() == QTcpSocket::ConnectedState)
        {
            //QByteArray message = "Hello from TCP!";
            tcpSocket->write(message);
            sendSourTextEdit->append("Sent TCP message: ");
        }
        else
        {
            sendSourTextEdit->append("TCP is not connected yet.");
        }
    }
}
void ProtocolSwitcher::judgeSaveState(QByteArray datagram)
{
    qDebug()<<1;
    if(static_cast<uint8_t>(datagram[2]) == static_cast<uint8_t>(2))
    {
        qDebug()<<2;
        // 屏蔽信号
        checkbox->blockSignals(true);

        checkbox->setChecked(!datagram[3]);
        // 恢复信号
        checkbox->blockSignals(false);
    }

}

void ProtocolSwitcher::TimerExample() {
    // 创建定时器对象
    timer = new QTimer(this);

    // 设置定时器间隔为1秒(1000毫秒)
    timer->setInterval(1000);

    // 连接定时器的timeout信号到槽函数
    connect(timer, &QTimer::timeout, this,[&]() {
        onSendMessage();
    });
}



void ProtocolSwitcher::loadConfigFromXml(const QString &filePath)
{
    // 创建 QDomDocument 对象
    QDomDocument doc;
    QFile file(filePath);

    if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) {
        qDebug() << "Failed to open file for reading.";
        return;
    }

    if (!doc.setContent(&file)) {
        qDebug() << "Failed to parse XML.";
        file.close();
        return;
    }
    file.close();

    // 获取根节点
    QDomElement root = doc.documentElement();
    QDomElement networkElement = root.firstChildElement("network");

    // 读取 udpA_softUnicast 配置
    QDomElement udpA_softUnicastElement = networkElement.firstChildElement("udpA_softUnicast");
    udpA_softUnicastHost = udpA_softUnicastElement.firstChildElement("host").text();
    int a=udpA_softUnicastElement.firstChildElement("port").text().toInt();
    udpA_softUnicastPort = a;

    // 读取 udpA_softMulticast 配置
    QDomElement udpA_softMulticastElement = networkElement.firstChildElement("udpA_softMulticast");
    udpA_softMulticastHost = udpA_softMulticastElement.firstChildElement("host").text();
    udpA_softMulticastPort = udpA_softMulticastElement.firstChildElement("port").text().toInt();

    // 读取 udpA_softBroadcast 配置
    QDomElement udpA_softBroadcastElement = networkElement.firstChildElement("udpA_softBroadcast");
    udpA_softBroadcastHost = udpA_softBroadcastElement.firstChildElement("host").text();
    udpA_softBroadcastPort = udpA_softBroadcastElement.firstChildElement("port").text().toInt();

    // 读取 udpB_softUnicast 配置
    QDomElement udpB_softUnicastElement = networkElement.firstChildElement("udpB_softUnicast");
    udpB_softUnicastHost = udpB_softUnicastElement.firstChildElement("host").text();
    udpB_softUnicastPort = udpB_softUnicastElement.firstChildElement("port").text().toInt();

    // 读取 udpB_softMulticast 配置
    QDomElement udpB_softMulticastElement = networkElement.firstChildElement("udpB_softMulticast");
    udpB_softMulticastHost = udpB_softMulticastElement.firstChildElement("host").text();
    udpB_softMulticastPort = udpB_softMulticastElement.firstChildElement("port").text().toInt();

    // 读取 udpB_softBroadcast 配置
    QDomElement udpB_softBroadcastElement = networkElement.firstChildElement("udpB_softBroadcast");
    udpB_softBroadcastHost = udpB_softBroadcastElement.firstChildElement("host").text();
    udpB_softBroadcastPort = udpB_softBroadcastElement.firstChildElement("port").text().toInt();

    QDomElement tcp = networkElement.firstChildElement("tcp");
    tcpHost = tcp.firstChildElement("host").text();
    tcpPort = tcp.firstChildElement("port").text().toInt();
    //    qDebug() << "XML configuration loaded from config.xml.";
}

void ProtocolSwitcher::onUdpDataReceived()
{
    while (udpSocket->hasPendingDatagrams())
    {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        outputTextEdit->append("Received UDP message: ");

//        // 使用 QDataStream 来解析接收到的数据
//                QDataStream stream(datagram);
//                stream.setByteOrder(QDataStream::LittleEndian);  // 根据发送端使用的字节顺序进行调整

//                Data receivedData;
//                stream >> receivedData.head
//                       >> receivedData.type
//                       >> receivedData.dataType
//                       >> receivedData.dataLong
//                       >> receivedData.info
//                       >> receivedData.tail;

//                // 打印接收到的数据字段
//                outputTextEdit->append("Received UDP Unicast message:");

//                // 将接收到的数据全部按字节打印（包括头、类型、info 和尾）
//                QByteArray allData;

//                // 将各个字段数据转换为 QByteArray 并拼接
//                allData.append(reinterpret_cast<const char*>(&receivedData.head), sizeof(receivedData.head));
//                allData.append(reinterpret_cast<const char*>(&receivedData.type), sizeof(receivedData.type));
//                allData.append(reinterpret_cast<const char*>(&receivedData.dataType), sizeof(receivedData.dataType));
//                allData.append(reinterpret_cast<const char*>(&receivedData.dataLong), sizeof(receivedData.dataLong));
//                allData.append(receivedData.info.toUtf8());
//                allData.append(reinterpret_cast<const char*>(&receivedData.tail), sizeof(receivedData.tail));

//                // 打印每个字节的十六进制表示（包括0x前缀）
//                QString hexString;
//                for (int i = 0; i < allData.size(); ++i) {
//                    //hexString += QString("0x%1 ").arg(static_cast<unsigned char>(allData[i]), 2, 16, QLatin1Char('0')).toUpper();
//                }
//QByteArray asciiData = datagram.toAscii();
        // 输出原始数据包内容（十六进制格式）
                QString hexString;
                for (int i = 0; i < datagram.size(); ++i) {
                    hexString += QString("0x%1 ").arg(static_cast<unsigned char>(datagram[i]), 2, 16, QLatin1Char('0')).toUpper();
                }
                qDebug() << "Received UDP packet (hex):" << hexString;
                // 输出十六进制字符串到 outputTextEdit
                outputTextEdit->append(hexString);
        judgeSaveState(datagram);
    }
}

void ProtocolSwitcher::onTcpDataReceived()
{
    QByteArray data = tcpSocket->readAll();
    outputTextEdit->append("Received TCP message: ");
    // 创建一个字符串，用于保存接收到的十六进制数据
    QString hexString;

    // 遍历接收到的每个字节，转换为十六进制
    for (int i = 0; i < data.size(); ++i) {
        // 将每个字节转换为 16 进制的字符串
        hexString.append(QString("0x%1 ").arg(static_cast<unsigned char>(data[i]), 2, 16, QChar('0')).toUpper());
    }

    // 将接收到的发送者信息和十六进制字符串添加到 QTextEdit 中
    outputTextEdit->append(hexString);
    judgeSaveState(data);
}

void ProtocolSwitcher::onTcpConnected()
{
    tcpSocket = tcpServer->nextPendingConnection();
    connect(tcpSocket, &QTcpSocket::readyRead, this, &ProtocolSwitcher::onTcpDataReceived);
    outputTextEdit->append("TCP connected.");
}

void ProtocolSwitcher::onTcpError(QAbstractSocket::SocketError socketError)
{
    Q_UNUSED(socketError);
    outputTextEdit->append("TCP connection failed: " + tcpSocket->errorString());
}

void ProtocolSwitcher::onCheckBoxToggled(bool checked)
{
    Control control;
    memset(&control, 0, sizeof(control));  // 清零整个结构体
    control.head=0xEB90;
    control.type=1;
    control.tail=0x0D0A;
    if (checked) {
        control.saveCon = 0;
    } else {
        control.saveCon = 1;
    }
    QByteArray message;
    QDataStream stream(&message, QIODevice::WriteOnly);
    stream << control.head
           << control.type
           << control.saveCon
           << control.tail;
    sendData(message);
}
void ProtocolSwitcher::onCycleCheckboxToggled(bool checked)
{
    if(checked)
    {
        // 启动定时器
        timer->start();
    }
    else
    {
        timer->stop();
    }
}
